package com.wy.controller;


import com.wy.common.Result;
import com.wy.pojo.CheckCodeMsgPo;
import com.wy.util.EmailSender;
import com.wy.util.RandomNumUtil;
import com.wy.util.VerificationCodeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 文件处理公共类
 */
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {

    @Value("${file.url}")
    private String url;

    @Autowired
    private EmailSender emailSender;


    @Value("${file.path}")
    String basePath;

    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file){
        log.info("文件信息为:{}",file.toString());

        //获取文件名
        String originalFilename = file.getOriginalFilename();
        //截取文件名的后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //生成uuid加上后缀作为新的文件名
        String fileName = UUID.randomUUID().toString() + suffix;

        //创建路径对象
        File dir = new File(basePath);
        //判断文件路径是否存在
        if(!dir.exists()){
            //不存在则创建一个目录
            dir.mkdirs();

        }
        try {
            //将文件转存到指定路径
            file.transferTo(new File(basePath+fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.success(fileName);
    }

    /**
     * 返回待url的图片
     * @param file
     * @return
     */
    @PostMapping("/upload2")
    public Result<String> upload2(MultipartFile file){
        log.info("文件信息为:{}",file.toString());

        //获取文件名
        String originalFilename = file.getOriginalFilename();
        //截取文件名的后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //生成uuid加上后缀作为新的文件名
        String fileName = UUID.randomUUID().toString() + suffix;

        //创建路径对象
        File dir = new File(basePath);
        //判断文件路径是否存在
        if(!dir.exists()){
            //不存在则创建一个目录
            dir.mkdirs();

        }
        try {
            //将文件转存到指定路径
            file.transferTo(new File(basePath+fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.success(url +fileName);
    }



    @GetMapping("/download")
    public void download(String name, HttpServletResponse response){
        try {
            //创建文件输入流读取文件
            FileInputStream inputStream = new FileInputStream(new File(basePath+name));

            //创建文件输出流
            ServletOutputStream outputStream = response.getOutputStream();

            response.setContentType("image/jpeg");

            int len = 0;
            byte[] bytes = new byte[1024];

            while( (len = inputStream.read(bytes)) != -1){
                outputStream.write(bytes,0,len);
                outputStream.flush();
            }

            //关闭资源
            outputStream.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @RequestMapping("/sendCode")
    public Result<String> sendCode(@RequestBody CheckCodeMsgPo checkCodeMsgPo, HttpServletRequest request) {

        HttpSession session = request.getSession();
        Map<String, List<String>> checkCode = (Map<String, List<String>>) session.getAttribute("checkCode");
        String phoneNum = checkCodeMsgPo.getEmail();
        if (null == phoneNum || "".equals(phoneNum)) {
            return null;
        }
        //随机生成四位的验证码
        checkCodeMsgPo.setCode(RandomNumUtil.getFourBitRandom());
        //自定义类设置进缓存
        setCodeSession(checkCodeMsgPo, request);

        //此处省略业务逻辑，发送手机验证码
        emailSender.send(checkCodeMsgPo.getEmail(), " 你好!<br/>" + "你的验证码是:" + checkCodeMsgPo.getCode() + "&nbsp;&nbsp;&nbsp;&nbsp;( 5分钟有效)");
        removeAttrbute(request.getSession(), "checkCode",checkCodeMsgPo);
        return Result.success("发送成功");
    }


    /**
     * 设置缓存
     *
     * @param checkCodeMsgPo
     * @param request
     */
    private void setCodeSession(CheckCodeMsgPo checkCodeMsgPo, HttpServletRequest request) {
        //获取缓存内存
        HttpSession session = request.getSession();

        Map<String, List<String>> checkCode = (Map<String, List<String>>) session.getAttribute("checkCode");
        List<String> codes = new ArrayList<>();
        if (null != checkCode) {
            //如果原来就存有session，直接拿出原来的验证码的list
            codes = checkCode.get(checkCodeMsgPo.getEmail());
        } else {
            checkCode = new HashMap<>();
        }

        //将新的验证码放入list中
        codes.add(checkCodeMsgPo.getCode());
        checkCode.put(checkCodeMsgPo.getEmail(), codes);

        //自定义类设置进缓存
        session.setAttribute("checkCode", checkCode);

    }

    /**
     * 指定有效时间内移除验证码
     * @param session        缓存
     * @param attrName       存入缓存的值
     * @param checkCodeMsgPo 封装的手机号码
     */
    public void removeAttrbute(final HttpSession session, final String attrName, final CheckCodeMsgPo checkCodeMsgPo) {

        //从Session提取手机号对应的验证码
        Map<String, List<String>> checkCode = (Map<String, List<String>>) session.getAttribute(attrName);
        List<String> codes = checkCode.get(checkCodeMsgPo.getEmail());

        ScheduledExecutorService schedu = Executors.newScheduledThreadPool(1);
        Runnable removeCode = new Runnable() {
            @Override
            public void run() {
                try {
                    // 移除session中list存的验证码元素
                    codes.remove(checkCodeMsgPo.getCode());
                    log.info("删除session中[" + checkCodeMsgPo.getEmail() + "]存的验证码:" + checkCodeMsgPo.getCode());
                } catch (Exception e) {
                    CheckCodeMsgPo checkCodeMsgPo = (CheckCodeMsgPo) session.getAttribute(attrName);
                    log.error(checkCodeMsgPo.getEmail() + "移除出错。");
                }
            }
        };
        //功能:创建并执行在给定延迟后启用的一次性操作。对removeCode任务暂停五分钟后执行
        schedu.schedule(removeCode, 5 * 60, TimeUnit.SECONDS);
        //启动一次顺序关闭，执行以前提交的任务，但不接受新任务。
        schedu.shutdown();

    }

    /**
     * 验证验证码的有效性
     * @param checkCodeMsgPo
     * @param request
     * @return
     * @throws
     */
    @RequestMapping("/verifyCode")
    public Result<String> verifyCode(@RequestBody CheckCodeMsgPo checkCodeMsgPo, HttpServletRequest request)  {
        Map<String, List<String>> checkCode = (Map<String, List<String>>) request.getSession().getAttribute("checkCode");

        if (null == checkCode) {
            return Result.error("验证码超时");
        }
        if (null != checkCode.get(checkCodeMsgPo.getEmail()) && checkCode.get(checkCodeMsgPo.getEmail()).size() > 0) {
            List<String> codes = checkCode.get(checkCodeMsgPo.getEmail());

            if (codes.contains(checkCodeMsgPo.getCode())) {
                //比对成功，移除元素以及清除缓存
                codes.remove(checkCodeMsgPo.getCode());
                request.getSession().removeAttribute("checkCode");
            } else {
                return Result.error("验证码错误！");
            }

        } else {
            return  Result.error("验证码已超时！");
        }

        return Result.success("验证成功！");
    }



    /**
     * 获取图片验证码
     * @return
     */
    @GetMapping("/getCode")
    public Result<String> getCode(HttpSession session){
        //截取文件名的后缀
        String suffix = ".png";
        //生成uuid加上后缀作为新的文件名
        String fileName = UUID.randomUUID() + suffix;
        //创建路径对象
        File dir = new File(basePath);
        //判断文件路径是否存在
        if(!dir.exists()){
            //不存在则创建一个目录
            dir.mkdirs();
        }
        try {
            String validateCode = null;
            FileOutputStream fileOutputStream = new FileOutputStream(new File(basePath+fileName));
            validateCode = VerificationCodeUtil.generateVerificationCode(200,50,5,fileOutputStream,"PNG" );
            log.info("验证码:"+validateCode);
            session.setAttribute("loginCode",validateCode);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.success(url + fileName);
    }



}
